package com.wg.db.repository.config;

import cn.hutool.core.util.ReflectUtil;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;

import com.wg.db.exception.DataException;
import com.wg.db.schema.SchemaHelper;
import com.wg.db.schema.SchemaTable;
import com.wg.db.sql.SqlRepository;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 配置仓库抽象基类，提供配置实体的加载、缓存和查询功能
 *
 * @param <B> 配置实体对应的Bean类型（实现IConfigBean）
 * @param <E> 配置实体类型（继承BaseConfig<B>）
 * @author 少爷123
 */
public abstract class BaseConfigRepository<B extends IConfigBean, E extends BaseConfig<B>> {
    private static final Log log = LogFactory.get();
    /**
     * 配置加载锁（防止并发加载）
     */
    private static final ReentrantLock LOAD_LOCK = new ReentrantLock();
    /**
     * 配置实体Class
     */
    private final Class<E> entityClass;
    /**
     * 配置Bean Class
     */
    private final Class<B> beanClass;
    /**
     * 表结构元数据
     */
    private final SchemaTable schemaTable;
    /**
     * 配置缓存（线程安全）
     */
    private volatile Map<Integer, E> entityMap;
    /**
     * 配置列表缓存（线程安全）
     */
    private volatile List<E> entityList;

    /**
     * 构造函数
     *
     * @param beanClass   配置Bean的Class
     * @param entityClass 配置实体的Class
     */
    public BaseConfigRepository(Class<B> beanClass, Class<E> entityClass) {
        this.beanClass = beanClass;
        this.entityClass = entityClass;
        this.schemaTable = SchemaHelper.getOrCreateSchema(beanClass);
    }

    /**
     * 加载配置（首次加载或手动刷新）
     *
     * @throws DataLoadException 加载失败时抛出
     */
    public void load() throws DataException {
        LOAD_LOCK.lock();
        try {
            List<B> beanList = SqlRepository.getAll(beanClass, schemaTable);
            Map<Integer, E> newMap = new ConcurrentHashMap<>(beanList.size());
            List<E> newList = new ArrayList<>(beanList.size());

            for (B bean : beanList) {
                E entity = createEntity(bean);
                if (entity != null) {
                    newMap.put(entity.getId(), entity);
                    newList.add(entity);
                }
            }

            // 原子更新缓存（保证可见性）
            this.entityMap = newMap;
            this.entityList = newList;
            log.info("配置加载完成: 表={}, 数量={}", getTableName(), beanList.size());
        } catch (Exception e) {
            throw new DataException("配置加载失败", e);
        } finally {
            LOAD_LOCK.unlock();
        }
    }

    /**
     * 手动触发配置刷新（立即生效）
     */
    public void refresh() {
        log.info("触发配置刷新...");
        load();
    }

    /**
     * 根据ID查询配置
     *
     * @param id 配置ID
     * @return 配置实体（不存在返回null）
     */
    public E get(int id) {
        return entityMap != null ? entityMap.get(id) : null;
    }

    /**
     * 获取第一个配置（按加载顺序）
     *
     * @return 第一个配置实体（无数据返回null）
     */
    public E getFirst() {
        return entityList != null && !entityList.isEmpty() ? entityList.get(0) : null;
    }

    /**
     * 获取最后一个配置（按加载顺序）
     *
     * @return 最后一个配置实体（无数据返回null）
     */
    public E getLast() {
        if (entityList == null || entityList.isEmpty()) {
            return null;
        }
        return entityList.get(entityList.size() - 1);
    }

    /**
     * 获取所有配置（按加载顺序）
     *
     * @return 配置实体列表（无数据返回空列表）
     */
    public List<E> getAll() {
        return entityList != null ? new ArrayList<>(entityList) : new ArrayList<>();
    }

    /**
     * 配置加载完成后触发（子类实现具体逻辑）
     */
    public abstract void onLoadComplete(boolean reload);

    /**
     * 获取配置表名
     *
     * @return 表名
     */
    public String getTableName() {
        return schemaTable.getModelTableName();
    }

    /**
     * 创建配置实体（子类可重写此方法自定义转换逻辑）
     *
     * @param bean 配置Bean
     * @return 配置实体
     */
    protected E createEntity(B bean) {
        try {
            return ReflectUtil.newInstance(entityClass, bean);
        } catch (Exception e) {
            log.error("配置实体实例化失败: bean={}", bean, e);
            return null;
        }
    }
}